/*
 * $Id: scp.c,v 1.12 2009/04/28 10:35:30 bagder Exp $
 *
 * Sample showing how to do a simple SCP transfer.
 */
//#include "libssh2_config.h"
#include <libssh2.h>
#include <libssh2_sftp.h>

# include <sys/socket.h>
# include <netinet/in.h>
#include <unistd.h>
# include <arpa/inet.h>
# include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>

#include <string>
#include <iostream>
#include <vector>

class Socket
{
public:
    Socket(const char* hostaddr_str){
        unsigned long hostaddr = inet_addr(hostaddr_str);
        socket_ = socket(AF_INET, SOCK_STREAM, 0);
        struct sockaddr_in sin;
        sin.sin_family = AF_INET;
        sin.sin_port = htons(22);
        sin.sin_addr.s_addr = hostaddr;
        if (connect(socket_, (struct sockaddr*)(&sin),
                    sizeof(struct sockaddr_in)) != 0) {
            fprintf(stderr, "failed to connect to the host!\n");
            throw ("failed to connect!");
        }
    }
    operator int(){
        return socket_;
    }
    ~Socket(){
        close(socket_);
    }
    
private:
    int socket_;
};

class Ssh2
{
public:
    Ssh2(){
        int rc = libssh2_init (0);
        if (rc != 0) {
            fprintf (stderr, "libssh2 initialization failed (%d)\n", rc);
            throw ("libssh2 initialization failed!");
        }
    }
    ~Ssh2(){
        libssh2_exit();
    }
};

class Ssh2Session
{
public:
    Ssh2Session(){
        session_ = libssh2_session_init();
        if ( !session_ ){
            throw "libssh2_session_init failed!";
        }
    }
    ~Ssh2Session(){
        libssh2_session_disconnect(session_, "Normal Shutdown, Thank you for playing");
        libssh2_session_free(session_);
    }
    int Startup(int socket){
        int rc = libssh2_session_startup(session_, socket);
        if (rc){
            fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
        }
    }
    int Authenticate(const char* username, const char* password){
        return libssh2_userauth_password(session_, username, password);
    }
    
    operator LIBSSH2_SESSION*(){
        return session_;
    }

private:
    LIBSSH2_SESSION* session_;
};
std::vector<std::string> GetDirContent(LIBSSH2_SESSION* session, const char* sftppath){
    LIBSSH2_SFTP *sftp_session = libssh2_sftp_init(session);
    LIBSSH2_SFTP_HANDLE *sftp_handle = libssh2_sftp_opendir(sftp_session, sftppath);
    if (!sftp_handle) {
        fprintf(stderr, "Unable to open dir with SFTP\n");
        return std::vector<std::string>();
    }
    std::vector<std::string> dirs;
    do {
        char mem[512];
        char longentry[512];
        LIBSSH2_SFTP_ATTRIBUTES attrs;
 
        /* loop until we fail */ 
        int rc = libssh2_sftp_readdir_ex(sftp_handle, mem, sizeof(mem),

                                     longentry, sizeof(longentry), &attrs);
        if(rc > 0) {
            if (LIBSSH2_SFTP_S_ISDIR(attrs.permissions)){
                dirs.push_back(std::string(mem, rc));
            }
        }
        else
            break;
 
    } while (1);
    return dirs;
}

    
std::string GetFileContent(LIBSSH2_SESSION* session, const char* scppath){
    /* Request a file via SCP */
    struct stat fileinfo;    
    LIBSSH2_CHANNEL* channel = libssh2_scp_recv(session, scppath, &fileinfo);

    if (!channel) {
        fprintf(stderr, "Unable to open a session\n");
    }

    off_t got = 0;
    std::string content;
    
    while(got < fileinfo.st_size) {
        char mem[1024];
        int amount=sizeof(mem);

        if((fileinfo.st_size -got) < amount) {
            amount = fileinfo.st_size -got;
        }

        int rc = libssh2_channel_read(channel, mem, amount);
        if(rc == amount) {
            std::string tmp(mem, rc);
            content += tmp;
        }
        else {
            fprintf(stderr, "libssh2_channel_read() failed: %d\n", rc);
            break;
        }
        got += rc;
    }
    libssh2_channel_free(channel);
    return content;
}


int main(int argc, char *argv[])
{
    const char *username="xxxx";
    const char *password="XXXXX";
    const char *scppath="/home/bzhu/.emacs";
    try
    {
        Socket sock("10.159.194.174");
        Ssh2 libssh2_instance;
        Ssh2Session session;
        session.Startup(sock);

        /* We could authenticate via password */
        if (session.Authenticate(username, password)){
            fprintf(stderr, "Authentication by password failed.\n");
            return -1;
        }
        //std::cout << GetFileContent(session, scppath) << std::endl;
        std::vector<std::string> dirs = GetDirContent(session, "/home/xxx/bak_config");
        for(std::vector<std::string>::const_iterator i = dirs.begin(); i != dirs.end(); ++i){
            std::cout << *i << std::endl;
        }
        
        
    }
    catch(const char* e)
    {
        std::cerr << "Exception occured! : " << e << std::endl;
        return -2;
    }

    return 0;
}
